/*
	gen_opening.cc	Game Opening Generator
	Copyright (c) 2001, 2002, 2003, 2004 Kriang Lerdsuwanakij
	email:		lerdsuwa@users.sourceforge.net

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "config.h"

#include <exception>
#include <stdexcept>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <ctype.h>
#include <set>
#include <string>

#include "board.h"
#include "opening.h"

#include "gtstream.h"

#ifdef _
#undef _
#endif

#ifdef N_
#undef N_
#endif

#include <libintl.h>
#define _(x) gettext(x)
#define N_(x) x

// Grab version number in VERSION variable
// Use same version number as main GRhino program
#undef VERSION
const char *
#include "scripts/version"
;

const char *prog_name = "gen_opening";
const char *prog_ver = VERSION;

int	num_data = 1;
byte_board_info *board_ptr;
byte_board_info *init_board_ptr;
char to_hex[] = "0123456789abcdef";

/* Board output format
	{ OPENING NAME, PLAYER AFTER OPENING,
	  { FINAL BOARD },
	  NUMBER OF MOVES, SAMPLE MOVE SEQUENCE } */

void	output_board(std::ostream &os, const byte_board_info *board, const char *name, 
		     int player, std::deque<int> &d)
{
					// No i18n for file output!
	if (num_data != 1)
		os << ",\n";

	os << "\t{ N_(\"" << name << "\"), " << player << ",\n";
	os << "\t  {";

	for (int y = 0; y < 8; ++y) {

		if (y != 0)
			os << "\n\t   ";

		for (int x = 0; x < 8; ++x) {
			os << std::setw(2)
			   << static_cast<int>(board->board[xy_to_pos(x, y)]);

			if (!(x == 7 && y == 7))
				os << ", ";
		}
	}

	os << "  },\n";
	os << "\t  " << d.size() << ", \"";
	for (size_t i = 0; i < d.size(); ++i) {
		os << "\\x" << to_hex[d[i]/16] << to_hex[d[i]%16];
	}
	os << "\" }";
}

int	main_real(int argc, char * /*argv*/[])
{
	if (argc != 1) {
		gtout(std::cout, _("%$ %$ - Game opening generator\n")) << prog_name << prog_ver;
		std::cout << _("(c) 2001, 2002, 2003, 2004 Kriang Lerdsuwanakij\n\n");
		gtout(std::cout, _("Usage:   %$ \n\n")) << prog_name;
		return 0;
	}

	board_ptr = new byte_board_info();
	init_board_ptr = new byte_board_info(&board_begin);

					// Try opening data file
	std::ifstream ifs("openings.txt");
	if (!ifs)
		throw std::runtime_error(_("cannot open file openings.txt"));

					// Generate header
	std::ofstream ofs("opening-dat.h");
	ofs << "/* Generated by gen_opening.  */\n\n";

					// Generate start board
	ofs << "opening_info opening_data[] = {\n";
	std::deque<int> dummy_d;
	output_board(ofs, init_board_ptr, "None", BLACK, dummy_d);

	std::set<std::string> name_set;

	for ( ; ; ) {
		std::string buffer;
		getline(ifs, buffer);

					// End of file
		if (!ifs)
			break;

					// Output board only for normalized
					// openings with C4 as first move
		if (buffer.size() > 2 && buffer[0] == 'C'
		    && buffer[1] == '4') {

					// Initialize board
			*board_ptr = *init_board_ptr;

					// Flip pieces
			int i = 0;
			int player = BLACK;
			std::deque<int> d;
			do {
					// A1 .. H8 for black
					// a1 .. h8 for white
				player = isupper(buffer[i]) ? BLACK : WHITE;
				int pos = xy_to_pos(toupper(buffer[i]) - 'A',
						    buffer[i+1] - '1');
				board_ptr->place_piece(player, pos);
					// Record sample sequence
				d.push_back(pos);
				i += 2;
			} while (buffer[i] != ' ');

					// Find next player after finish
					// opening
			player = -player;
			if (!board_ptr->can_play(player))
				player = -player;

					// Skip spaces
			while (buffer[i] == ' ')
				i++;

					// Get opening name
			int imax = buffer.size();
			int j = 0;
			std::string name;
			for ( ; ; ) {
				if (i == imax)
					break;

					// Skip "**" (newer openings)
				if (imax-i >= 2 && buffer[i] == '*' && buffer[i+1] == '*')
					i += 2;
					// Skip "(t3)" (diagonal openings)
				else if (imax-i >= 4 && buffer[i] == '(' && buffer[i+1] == 't')
					i += 4;
					// Skip consecutive spaces
				else if (buffer[i] == ' ' && j > 0 && name[j-1] == ' ')
					i++;
				else {
					if (buffer[i] == '\"') {
						name += '\\';
						j++;
					}
					name += buffer[i];
					i++;
					j++;
				}
			}

					// Remove trailing space
			if (name[j-1] == ' ')
				name.erase(j-1, 1);

					// Output board if not a duplicate
					// of previous opening
			if (name_set.insert(name).second) {
				num_data++;
				output_board(ofs, board_ptr, name.c_str(),
					     player, d);
			}
		}
	}

	ofs << "\n};\n\n";
	ofs << "const int NUM_OPENING_DATA = " << num_data << ";\n";
	return 0;
}

int	main(int argc, char *argv[])
{
	try {
		return main_real(argc, argv);
	}
	catch (std::exception &e) {
		std::cout << std::flush;
		gtout(std::cerr, _("%$: %$\n")) << prog_name << e.what();
	}
	catch (const char *s) {
		std::cout << std::flush;
		gtout(std::cerr, _("%$: exception %$\n")) << prog_name << s;
	}
	catch (...) {
		std::cout << std::flush;
		gtout(std::cerr, _("%$: unknown exception\n")) << prog_name;
	}
	return 1;
}
